bitkeeper revision 1.225 (3ec0d7a2BpgJXl0j-8Y1KilL1argzw)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 13 May 2003 11:31:46 +0000 (11:31 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 13 May 2003 11:31:46 +0000 (11:31 +0000)
lib.h, network.c, lib.c, kernel.c:
  A better method for calculating virtual MAC addresses. Dom0/VIF0 (the boot VIF) can be forced to use the physical MAC address by specifying 'phys_bootmac' on Xen's command line.

xen/common/kernel.c
xen/common/lib.c
xen/common/network.c
xen/include/xeno/lib.h

index 0b8e693e97bc2854ee383f5368605470a2b94a89..5b1d0f9804d2dce02016ae53f92f2dda77c314a1 100644 (file)
@@ -40,21 +40,23 @@ unsigned int opt_ser_baud = 9600;  /* default baud for COM1 */
 unsigned int opt_dom0_mem = 16000; /* default kbytes for DOM0 */
 unsigned int opt_ne_base = 0; /* NE2k NICs cannot be probed */
 unsigned char opt_ifname[10] = "eth0";
-int opt_noht=0, opt_noacpi=0, opt_nosmp;
+int opt_noht=0, opt_noacpi=0, opt_nosmp=0;
+int opt_phys_bootmac=0; /* Is DOM0/VIF0 allocated the physical MAC address? */
 enum { OPT_IP, OPT_STR, OPT_UINT, OPT_BOOL };
 static struct {
     unsigned char *name;
     int type;
     void *var;
 } opts[] = {
-    { "console",  OPT_UINT, &opt_console },
-    { "ser_baud", OPT_UINT, &opt_ser_baud },
-    { "dom0_mem", OPT_UINT, &opt_dom0_mem }, 
-    { "ne_base",  OPT_UINT, &opt_ne_base },
-    { "ifname",   OPT_STR,  &opt_ifname },
-    { "noht",     OPT_BOOL, &opt_noht },
-    { "noacpi",   OPT_BOOL, &opt_noacpi },
-    { "nosmp",    OPT_BOOL, &opt_nosmp },
+    { "console",      OPT_UINT, &opt_console },
+    { "ser_baud",     OPT_UINT, &opt_ser_baud },
+    { "dom0_mem",     OPT_UINT, &opt_dom0_mem }, 
+    { "ne_base",      OPT_UINT, &opt_ne_base },
+    { "ifname",       OPT_STR,  &opt_ifname },
+    { "noht",         OPT_BOOL, &opt_noht },
+    { "noacpi",       OPT_BOOL, &opt_noacpi },
+    { "nosmp",        OPT_BOOL, &opt_nosmp },
+    { "phys_bootmac", OPT_BOOL, &opt_phys_bootmac },
     { NULL,       0,        NULL     }
 };
 
index c871341b7f5ecad99da7fdd9264f56b3652bf12a..3d7cc8c00e24240414a3f62f58102589bbfe2812 100644 (file)
@@ -525,3 +525,67 @@ __udivdi3(a, b)
 
         return (__qdivrem(a, b, (u64 *)0));
 }
+
+
+
+
+/* HASH/RANDOMISATION FUNCTION
+ * Based on lookup2.c, by Bob Jenkins, December 1996, Public Domain.
+ * You can use this free for any purpose.  It has no warranty.
+ * See http://burlteburtle.net/bob/hash/evahash.html 
+ */
+
+typedef unsigned long ub4;
+
+#define mix(a,b,c)                                      \
+    do {                                                \
+        a -= b; a -= c; a ^= (c>>13);                   \
+        b -= c; b -= a; b ^= (a<< 8);                   \
+        c -= a; c -= b; c ^= ((b&0xffffffff)>>13);      \
+        a -= b; a -= c; a ^= ((c&0xffffffff)>>12);      \
+        b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \
+        c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \
+        a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \
+        b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \
+        c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \
+    } while ( 0 )
+
+unsigned long hash(unsigned char *k, unsigned long len)
+{
+    unsigned long a, b, c, l;
+
+    l = len;
+    a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
+    c = 0xa5a5a5a5;      /* another arbitrary value (KAF, 13/5/03) */
+
+    while ( l >= 12 )
+    {
+        a += (k[0] + ((ub4)k[1]<<8) + ((ub4)k[2]<<16)  + ((ub4)k[3]<<24));
+        b += (k[4] + ((ub4)k[5]<<8) + ((ub4)k[6]<<16)  + ((ub4)k[7]<<24));
+        c += (k[8] + ((ub4)k[9]<<8) + ((ub4)k[10]<<16) + ((ub4)k[11]<<24));
+        mix(a,b,c);
+        k += 12; l -= 12;
+    }
+
+    c += len;
+    switch ( l )
+    {
+    case 11: c+=((ub4)k[10]<<24);
+    case 10: c+=((ub4)k[9]<<16);
+    case 9 : c+=((ub4)k[8]<<8);
+        /* the first byte of c is reserved for the length */
+    case 8 : b+=((ub4)k[7]<<24);
+    case 7 : b+=((ub4)k[6]<<16);
+    case 6 : b+=((ub4)k[5]<<8);
+    case 5 : b+=k[4];
+    case 4 : a+=((ub4)k[3]<<24);
+    case 3 : a+=((ub4)k[2]<<16);
+    case 2 : a+=((ub4)k[1]<<8);
+    case 1 : a+=k[0];
+        /* case 0: nothing left to add */
+    }
+
+    mix(a,b,c);
+
+    return c;
+}
index f7c5f3b7c270a66693c2d13982a89709c1fefb1f..9a2d5eef8a0dcb04b7f64b8f88c34ea0b490766d 100644 (file)
@@ -69,7 +69,9 @@ net_vif_t *create_net_vif(int domain)
     net_vif_t *new_vif = NULL;
     net_ring_t *new_ring = NULL;
     struct task_struct *p = NULL;
-    unsigned long flags;
+    unsigned long flags, vmac_hash;
+    unsigned char vmac_key[ETH_ALEN + 4 + 2];
+    extern int opt_phys_bootmac;
 
     if ( !(p = find_domain_by_id(domain)) )
         return NULL;
@@ -104,13 +106,40 @@ net_vif_t *create_net_vif(int domain)
     spin_lock_init(&new_vif->rx_lock);
     spin_lock_init(&new_vif->tx_lock);
 
-    /*
-     * Virtual MAC is a hash of the real physical MAC. Chosen so that the 
-     * first vif of domain 0 gets the physical MAC address.
-     */
-    memcpy(new_vif->vmac, the_dev->dev_addr, ETH_ALEN);
-    ((unsigned short *)new_vif->vmac)[1] ^= htons(p->domain);
-    ((unsigned short *)new_vif->vmac)[2] ^= htons(dom_vif_idx);
+    if ( opt_phys_bootmac && (p->domain == 0) && (dom_vif_idx == 0) )
+    {
+        /*
+         * DOM0/VIF0 may get the real physical MAC address, so that
+         * users can easily get a Xenoserver up and running by using an
+         * existing DHCP entry.
+         */
+        memcpy(new_vif->vmac, the_dev->dev_addr, ETH_ALEN);
+    }
+    else
+    {
+        /*
+         * Most VIFs get a random MAC address with a "special" vendor id.
+         * We try to get MAC addresses to be unique across multiple servers
+         * by including the physical MAC address in the hash.
+         * However, the same machine with the same dom_id and vif_id should
+         * always get the same virtual MAC address.
+         * 
+         * NB. The vendor is currently an "obsolete" one that used to belong
+         * to DEC (AA-00-00). Using it is probably a bit rude :-)
+         * 
+         * NB2. The first bit of the first random octet is set to zero for
+         * all dynamic MAC addresses. This may allow us to manually specify
+         * MAC addresses for some VIFs with no fear of clashes.
+         */
+        memcpy(&vmac_key[0], the_dev->dev_addr, ETH_ALEN);
+        *(__u32 *)(&vmac_key[ETH_ALEN+0]) = htonl(p->domain);
+        *(__u16 *)(&vmac_key[ETH_ALEN+4]) = htons(dom_vif_idx);
+        vmac_hash = hash(vmac_key, ETH_ALEN+4+2);
+        memcpy(new_vif->vmac, "\xaa\x00\x00", 3);
+        new_vif->vmac[3] = (vmac_hash >> 16) & 0xef; /* First bit is zero. */
+        new_vif->vmac[4] = (vmac_hash >>  8) & 0xff;
+        new_vif->vmac[5] = (vmac_hash >>  0) & 0xff;
+    }
 
     p->net_vif_list[dom_vif_idx] = new_vif;
     
index a9eeda6716bb900cb5772efd603656494554c7bd..9f97ad953037bac60876e35e155222c3eedb65fa 100644 (file)
@@ -54,4 +54,7 @@ long simple_strtol(const char *cp,char **endp,unsigned int base);
 unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base);
 long long simple_strtoll(const char *cp,char **endp,unsigned int base);
 
+/* Produce a 32-bit hash from a key string 'k' of length 'len' bytes. */
+unsigned long hash(unsigned char *k, unsigned long len);
+
 #endif /* __LIB_H__ */